/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse.misc;

import java.util.*;
import java.io.*;
import java.sql.*;

import nfse.*;

public class IndexMover {

	private MetaDatabase mdb = null;

	public IndexMover(String dbHost, String dbPort, String dbUser, String dbPassword) throws Exception {
        mdb = MetaDatabase.create();
	}

	public void moveIndices(int month, int day, int year, int run, int sensor, String newRoot) {
		try {
			String sql =
				"select * from Static_Indices where Month="
					+ month
					+ " and Day="
					+ day
					+ " and Year="
					+ year
					+ " and Run="
					+ run
					+ " and Sensor_ID="
					+ sensor;
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveIndex(month, day, year, run, rs.getInt("Field_ID"), sensor, newRoot);
			}
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void moveIndices(int month, int day, int year, int sensor, int run, int field, String newRoot) {
		try {
			String sql =
				"select * from Static_Indices where Month="
					+ month
					+ " and Day="
					+ day
					+ " and Year="
					+ year
					+ " and Run="
					+ run
					+ " and Sensor_ID="
					+ sensor
					+ " and Field_ID="
					+ field;
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveIndex(month, day, year, run, rs.getInt("Field_ID"), sensor, newRoot);
			}
			rs.close();
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void moveIndices(int month, int day, int year, int sensor, String newRoot) {
		try {
			String sql =
				"select * from Static_Indices where Month="
					+ month
					+ " and Day="
					+ day
					+ " and Year="
					+ year
					+ " and Sensor_ID="
					+ sensor;
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveIndex(month, day, year, rs.getInt("Run"), rs.getInt("Field_ID"), sensor, newRoot);
			}
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void moveIndices(int month, int day, int year, String newRoot) {
		try {
			String sql = "select * from Static_Indices where Month=" + month + " and Day=" + day + " and Year=" + year;
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveIndex(month, day, year, rs.getInt("Run"), rs.getInt("Field_ID"), rs.getInt("Sensor_ID"), newRoot);
			}
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void moveIndices(java.sql.Date start, java.sql.Date end, String newRoot) {
		try {
			String sql = "select * from Static_Indices where Index_Date between '" + start + "' and '" + end + "'";
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveIndex(
					rs.getInt("Month"),
					rs.getInt("Day"),
					rs.getInt("Year"),
					rs.getInt("Run"),
					rs.getInt("Field_ID"),
					rs.getInt("Sensor_ID"),
					
					newRoot);
			}
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void moveIndex(int month, int day, int year, int run, int field, int sensor, String newRoot) {
		try {
			IndexInfo info = mdb.getStaticIndexInfo(month, day, year, run, field, sensor);
			if (info == null) {
				System.out.println("No entry exists for the given information.");
				return;
			}
			if (info.getDbPath().endsWith("/") != true)
				info.setDbPath(info.getDbPath() + "/");
			System.out.println("Moving the following index:");
			System.out.println(info.toString());
			StringTokenizer st = new StringTokenizer(info.getDbPath(), "/");
			String oldRoot = "/";
			if (!newRoot.endsWith("/"))
				newRoot = newRoot + "/";
			int numDirs = st.countTokens() - 6;
			for (int i = 0; i < numDirs; i++) {
				oldRoot += st.nextToken() + "/";
			}
			String path = "";
			File dir = new File(newRoot + path);
			if (!dir.exists())
				dir.mkdir();
			String typeDirName = st.nextToken();
			path += typeDirName + "/";
			dir = new File(newRoot + path);
			if (!dir.exists())
				dir.mkdir();
			String sensorDirName = st.nextToken();
			path += sensorDirName + "/";
			dir = new File(newRoot + path);
			if (!dir.exists())
				dir.mkdir();
			String indexDirName = st.nextToken();
			path += indexDirName + "/";
			dir = new File(newRoot + path);
			if (!dir.exists())
				dir.mkdir();
			String yearDirName = st.nextToken();
			path += yearDirName + "/";
			dir = new File(newRoot + path);
			if (!dir.exists())
				dir.mkdir();
			String dbDirName = st.nextToken();
			path += dbDirName + "/";
			dir = new File(newRoot + path);
			if (!dir.exists())
				dir.mkdir();
			String fieldDirName = st.nextToken();
			String newPath = newRoot + path;
			String oldPath = oldRoot + path;

			// Don't move if target and source are the same	
			if (oldPath.compareTo(newPath) == 0) {
				System.out.println("Paths are the same, returning");
				return;
			}

			String archName = fieldDirName + ".tar";
			PrintWriter out =
				new PrintWriter(new FileWriter(System.getProperty("user.home") + "/" + fieldDirName + ".sh"));
			out.println("cd " + oldPath);
			out.println("tar -cf " + archName + " " + fieldDirName + " --atime-preserve");
			out.println("mv " + archName + " " + newPath);
			out.println("cd " + newPath);
			out.println("tar -xf " + archName + " --atime-preserve");
			//out.println("rm " + archName);
			out.close();
			Process p = Runtime.getRuntime().exec("sh " + System.getProperty("user.home") + "/" + fieldDirName + ".sh");
			int val = p.waitFor();
			
			Vector temp = new Vector();
			LineNumberReader fileIndexIn = new LineNumberReader(new FileReader(newPath + fieldDirName + "/file.index"));
			String line = fileIndexIn.readLine();
			while (line != null) {
				line = line.substring(0,4) + newRoot + line.substring(oldRoot.length()+4);
				line = fileIndexIn.readLine();
			}
			fileIndexIn.close();
			PrintWriter fileIndexOut = new PrintWriter(new FileWriter(newPath + fieldDirName + "/file.index"));
			for (int i = 0; i < temp.size(); i++)
				out.println((String)temp.elementAt(i));
			fileIndexOut.close();
			
			mdb.removeStaticIndex(info.getSensorId(), info.getField(), info.getMonth(), info.getDay(), info.getYear(), info.getRun());
			info.setDbPath(newPath + fieldDirName);
			mdb.addStaticIndex(info);
			File script = new File(System.getProperty("user.home") + "/" + fieldDirName + ".sh");
			script.delete();
			p = Runtime.getRuntime().exec("rm " + archName + ";rm -Rf " + oldPath + fieldDirName);
			p.waitFor();
		} catch (Exception E) {
			E.printStackTrace();
		}
	}

	public void moveDataFile(int month, int day, int year, int run, int sensor, String newRoot) {
		try {
			DataInfo info = mdb.getDataInfo(month, day, year, run, sensor);
			if (info == null) {
				System.out.println("No entry exists for the given information.");
				return;
			} 
			System.out.println("Moving the following data:");
			System.out.println(info.toString());
			StringTokenizer st = new StringTokenizer(info.getDataPath(), "/");
			String oldRoot = "";
			int numDirs = st.countTokens() - 4;
			for (int i = 0; i < numDirs; i++) {
				oldRoot += "/" + st.nextToken();
			}
			String newPath = newRoot;
			if (newPath.endsWith("/"))
				newPath = newPath.substring(0, newPath.length() - 1);
			String oldPath = info.getDataPath();
			while (st.hasMoreTokens()) {
				File dir = new File(newPath);
				if (!dir.exists())
					dir.mkdir();
				if ((!dir.exists()) || ((dir.exists()) && (!dir.isDirectory()))) {
					System.err.println("Could not create dir, exiting");
					return;
				}
				newPath += "/" + st.nextToken();
			}

			if (oldPath.compareTo(newPath) == 0) {
				System.out.println("Paths are the same, returning");
				return;
			}

			boolean isZipped = false;
			File old = new File(oldPath);
			if (!old.exists()) { // Check to see if it is gzipped
				File oldZipped = new File(oldPath + ".gz");
				if (oldZipped.exists()) {
					// The target file is gzipped
					isZipped = true;
				}
			}
			Process p = null;
			if (!isZipped) {
				System.out.println("Copying " + oldPath + " to " + newPath + "...");
				p = Runtime.getRuntime().exec("cp " + oldPath + " " + newPath);
			} else {
				System.out.println("Copying " + oldPath + ".gz to " + newPath + ".gz...");
				p = Runtime.getRuntime().exec("cp " + oldPath + ".gz " + newPath + ".gz");
			}
			int val = p.waitFor();
			System.out.println("...copy done.");

			String sql =
				"select * from Static_Indices where Index_Date='"
					+ year
					+ "-"
					+ month
					+ "-"
					+ day
					+ "' and Run="
					+ run
					+ " and Sensor_ID="
					+ sensor;
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				String dbInfo = rs.getString("DB_Path");
				if (!dbInfo.endsWith("/"))
					dbInfo = dbInfo + "/";
				dbInfo = dbInfo + "info";
				File file = new File(dbInfo);
				if (file.exists()) {
					LineNumberReader in = new LineNumberReader(new FileReader(dbInfo));
					Vector contents = new Vector();
					String line = in.readLine();
					while (line != null) {
						if (line.startsWith("dataFile")) {
							contents.addElement(new String("dataFile " + newPath)); 
						}
						else
							contents.addElement(line);	
						line = in.readLine();
					}
					in.close();
					PrintWriter out = new PrintWriter(new FileWriter(dbInfo));
					for (int i = 0; i < contents.size(); i++) 
						out.println((String)contents.elementAt(i));
					out.close();
				}	
			}
			System.out.println("Updating metadata...");
			mdb.removeData(info.getMonth(), info.getDay(), info.getYear(), info.getRun(), info.getSensor());
			info.setDataPath(newPath);
			//if (isZipped)
			//	p = Runtime.getRuntime().exec("gunzip " + newPath + ".gz");
			mdb.addData(info);
			System.out.println("...update done.");
			if (!isZipped) {
				System.out.println("Removing " + oldPath + "...");
				p = Runtime.getRuntime().exec("rm " + oldPath);
			} else {
				System.out.println("Removing " + oldPath + ".gz...");
				p = Runtime.getRuntime().exec("rm " + oldPath + ".gz");
			}
			val = p.waitFor();
			System.out.println("...remove done");
		} catch (Exception E) {
			E.printStackTrace();
		}
	}

	public void moveDataFiles(int month, int day, int year, int sensor, String newRoot) {
		try {
			String sql =
				"select * from Data_Info where Month="
					+ month
					+ " and Day="
					+ day
					+ " and Year="
					+ year
					+ " and Sensor_ID="
					+ sensor;
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveDataFile(month, day, year, rs.getInt("Run"), sensor, newRoot);
			}
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void moveDataFiles(int month, int day, int year, String newRoot) {
		try {
			String sql = "select * from Data_Info where Month=" + month + " and Day=" + day + " and Year=" + year;
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveDataFile(month, day, year, rs.getInt("Run"), rs.getInt("Sensor_ID"), newRoot);
			}
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public void moveDataFiles(java.sql.Date start, java.sql.Date end, String newRoot) {
		try {
			String sql = "select * from Data_Info where Index_Date between '" + start + "' and '" + end + "'";
			Statement s = mdb.createStatement();
			ResultSet rs = s.executeQuery(sql);
			while (rs.next()) {
				this.moveDataFile(
					rs.getInt("Month"),
					rs.getInt("Day"),
					rs.getInt("Year"),
					rs.getInt("Run"),
					rs.getInt("Sensor_ID"),
					newRoot);
			}
			s.close();
		} catch (SQLException sqle) {
			sqle.printStackTrace();
		}
	}

	public static void main(String[] args) {
		System.out.println("Index mover 1.0");
		if (args.length < 6) {
			System.out.println(
				"Usage: IndexMover dbURL dbUser dbPassword [-index | -data ] start_date end_date new_root");
			System.out.println(
				"       IndexMover dbURL dbUser dbPassword [-index | -data ] month day year [sensor [run [field]]] new_root");
			return;
		}
		try {
			IndexMover mover = new IndexMover(args[0], args[1], args[2], args[3]);
			String newRoot = args[args.length - 1];
			if (!args[3].startsWith("-")) {
				if (true) {
					System.out.println("Joint index and data move not yet supported.");
					return;
				}
				switch (args.length) {
					case 6 :
						StringTokenizer st = new StringTokenizer(args[3], "-");
						if (st.countTokens() != 3) {
							System.err.println("Start date must be of the form 'yyyy-mm-dd'");
							return;
						}
						java.sql.Date startDate = java.sql.Date.valueOf(args[3]);
						st = new StringTokenizer(args[4], "-");
						if (st.countTokens() != 3) {
							System.err.println("End date must be of the form 'yyyy-mm-dd'");
							return;
						}
						java.sql.Date endDate = java.sql.Date.valueOf(args[4]);
						mover.moveIndices(startDate, endDate, newRoot);
						break;
					case 7 :
						mover.moveIndices(
							Integer.parseInt(args[3]),
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							newRoot);
						break;
					case 8 :
						mover.moveIndices(
							Integer.parseInt(args[3]),
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							newRoot);
						break;
					case 9 :
						mover.moveIndices(
							Integer.parseInt(args[3]),
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							Integer.parseInt(args[7]),
							newRoot);
						break;
					case 10 :
						mover.moveIndices(
							Integer.parseInt(args[3]),
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							Integer.parseInt(args[7]),
							Integer.parseInt(args[8]),
							newRoot);
						break;
				}
			} else if (args[3].compareTo("-index") == 0) {
				switch (args.length) {
					case 7 :
						StringTokenizer st = new StringTokenizer(args[4], "-");
						if (st.countTokens() != 3) {
							System.err.println("Start date must be of the form 'yyyy-mm-dd'");
							return;
						}
						java.sql.Date startDate = java.sql.Date.valueOf(args[4]);
						st = new StringTokenizer(args[5], "-");
						if (st.countTokens() != 3) {
							System.err.println("End date must be of the form 'yyyy-mm-dd'");
							return;
						}
						java.sql.Date endDate = java.sql.Date.valueOf(args[5]);
						mover.moveIndices(startDate, endDate, newRoot);
						break;
					case 8 :
						mover.moveIndices(
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							newRoot);
						break;
					case 9 :
						mover.moveIndices(
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							Integer.parseInt(args[7]),
							newRoot);
						break;
					case 10 :
						mover.moveIndices(
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							Integer.parseInt(args[7]),
							Integer.parseInt(args[8]),
							newRoot);
						break;
					case 11 :
						mover.moveIndices(
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							Integer.parseInt(args[7]),
							Integer.parseInt(args[8]),
							Integer.parseInt(args[9]),
							newRoot);
						break;
					default :
						System.out.println("Unsupported parameters.");
						return;
				}
			} else if (args[3].compareTo("-data") == 0) {
				switch (args.length) {
					case 7 : // Move data files by date range
						StringTokenizer st = new StringTokenizer(args[4], "-");
						if (st.countTokens() != 3) {
							System.err.println("Start date must be of the form 'yyyy-mm-dd'");
							return;
						}
						java.sql.Date startDate = java.sql.Date.valueOf(args[4]);
						st = new StringTokenizer(args[5], "-");
						if (st.countTokens() != 3) {
							System.err.println("End date must be of the form 'yyyy-mm-dd'");
							return;
						}
						java.sql.Date endDate = java.sql.Date.valueOf(args[5]);
						mover.moveDataFiles(startDate, endDate, newRoot);
						break;
					case 8 : // Move data files by single date
						mover.moveDataFiles(
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							newRoot);
						break;
					case 9 : // Move data files by date and sensor
						mover.moveDataFiles(
							Integer.parseInt(args[4]),
							Integer.parseInt(args[5]),
							Integer.parseInt(args[6]),
							Integer.parseInt(args[7]),
							newRoot);
						break;
					default :
						System.out.println("Unsupported parameters.");
						return;
				}
			} else {
				System.err.println("Bad parm (" + args[3] + "), must be '-index', '-data' or a start_date.");
				return;
			}
		} catch (Exception E) {
			E.printStackTrace();
		}
	}
}
